package com.qsxc.system.log;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * 日志打印工具类
 *
 * @author
 */
@Slf4j
public class LogUtil {
    private static Map<String, Logger> loggersCache = new HashMap<>();

    private static ThreadLocal<ArrayList<LogBean>> logBuffer = new ThreadLocal<ArrayList<LogBean>>();

    public static void info(String loginfo) {
        ArrayList<LogBean> list = logBuffer.get();
        if (list != null) {
            list.add(new LogBean(loginfo, Level.INFO, getInvokedFromClassName()));
        } else {
            log.info(loginfo);
        }
    }

    public static void warn(String loginfo) {
        ArrayList<LogBean> list = logBuffer.get();
        if (list != null) {
            list.add(new LogBean(loginfo, Level.WARN, getInvokedFromClassName()));
        } else {
            log.warn(loginfo);
        }
    }

    public static void debug(String loginfo) {
        ArrayList<LogBean> list = logBuffer.get();
        if (list != null) {
            list.add(new LogBean(loginfo, Level.DEBUG, getInvokedFromClassName()));
        } else {
            log.debug(loginfo);
        }
    }

    public static void error(String loginfo, Exception e) {
        ArrayList<LogBean> list = logBuffer.get();
        if (list != null) {
            list.add(new LogBean(loginfo, Level.ERROR, e, getInvokedFromClassName()));
        } else {
            log.error(loginfo, e);
        }
    }

    public static void error(String loginfo) {
        ArrayList<LogBean> list = logBuffer.get();
        if (list != null) {
            list.add(new LogBean(loginfo, Level.ERROR, getInvokedFromClassName()));
        } else {
            log.error(loginfo);
        }
    }

    public static void init() {
        ArrayList<LogBean> list = logBuffer.get();
        if (list == null) {
            list = new ArrayList<LogBean>();
            logBuffer.set(list);
        }
    }

    /**
     * 输出一个Rest请求的所有日志
     */
    public static void printAll() {
        ArrayList<LogBean> list = logBuffer.get();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Long timeStart = list.get(0).getTime();
        Long timeEnd = list.get(list.size() - 1).getTime();
        for (LogBean item : list) {
            Logger logger = getLogger(item.getClassName());
            if (logger == null) {
                continue;
            }
            if (Level.INFO.equals(item.getLevel())) {
                logger.info(item.getInfo());
            } else if (Level.DEBUG.equals(item.getLevel())) {
                logger.debug(item.getInfo());
            } else if (Level.WARN.equals(item.getLevel())) {
                logger.warn(item.getInfo());
            } else if (Level.ERROR.equals(item.getLevel())) {
                if (item.getE() != null) {
                    logger.error(item.getInfo(), item.getE());
                } else {
                    logger.error(item.getInfo());
                }
            } else {
                logger.info(item.getInfo());
            }
        }
        list.clear();
        log.info("处理耗时:{}毫秒", timeEnd - timeStart);
    }

    public static void remove() {
        logBuffer.remove();
    }

    /**
     * 获取写入日志方法的类的名称
     */
    private static String getInvokedFromClassName() {
        StackTraceElement ste = Thread.currentThread().getStackTrace()[3];
        return ste.getClassName();
    }

    /**
     * 获取指定类所对应的{@link Logger}对象，如果没有创建则创建一个新的
     *
     * @param clazzName 指定类完整名称
     * @return 对应的{@link Logger}对象
     */
    private static synchronized Logger getLogger(String clazzName) {
        Logger logger = loggersCache.get(clazzName);
        if (logger == null) {
            synchronized (loggersCache) {
                if (!loggersCache.containsKey(clazzName)) {
                    logger = LoggerFactory.getLogger(clazzName);
                    loggersCache.put(clazzName, logger);
                } else {
                    logger = loggersCache.get(clazzName);
                }
            }
        }
        return logger;
    }
}
